// SuperHeros.java

package com.ibm.tspaces.examples.simple;

import  java.util.*;
import  java.text.*;
import  java.io.*;
import  com.ibm.tspaces.*;
import  com.ibm.tspaces.query.*;

/*
**  Licensed Materials - Property of IBM
**
**  (C) COPYRIGHT IBM Corp. 1996, 1997  All rights reserved
**
**  US Government Users Restricted Rights - Use, duplication or
**  disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
**
**/


/**
** This example is based on the SuperHeros example that
** was in one of the TSpaces publications
**
**   One of the differentiating features of TSpaces is that it 
**   builds an index on each named field in a tuple.  
**   This enables clients to request tuples based solely on values 
**   in fields with a given name, regardless of the structure of 
**   the rest of the tuple (or even the position of the named 
**   field within the tuple).  
**   For example, an index query of the form ("foo",8) will select 
**   all tuples (of any format) containing a field named "foo" 
**   with the integer value 8.  It is also possible to specify a 
**   range of values to be found in the index.Queries:
** <p>   	 
**  
**   The current implementation of TSpaces provides 
**   four types of queries: Match, Index, And and Or queries.  
**   A Match query performs structural or object compatibility 
**   matching (depending on its argument), 
**   while an Index query performs a named-field query.  
**   And and Or queries can be used to combine these and 
**   build complex query trees.  
**
**
** @see TupleSpace
** @version $Revision: 2.1 $ $Date: 1999/11/05 22:22:40 $
** @author John Thomas 
** 
*/

public class SuperHeros implements Serializable {
	static String _host = 	"localhost";

  /*
  ***************************************************************************
  ** ** init    **
  ** *************
  */
  /**
  **  Here is where we will write the initial data to the 
  **  tuplespace
  **
  **  Then we will do the queries.
  */

public void 
init() {
	
    TupleSpace ts1=null;
    TupleSpace ts2=null;
    
    // declare the tuples we'll use for the query and the result.
    Tuple	queryTuple, resultTuple, resultSetTuple;  	
    try { 	
      ts1 = new TupleSpace("SuperHero1",_host);
		  ts2 = new TupleSpace("SuperHero2",_host);
    	ts1.deleteAll();
    	ts2.deleteAll();
	  } catch ( TupleSpaceException tse) {
	  	Debug.out(0,tse);
      System.exit(1);
	  }
  try {  

    Rock  mysteryRock = new Rock();   // Create a new rock of unknown type for Superman
    ts1.write( "Superman", new Integer(75), mysteryRock );
    ts1.write( "Superman", new Integer(75), new Rock("Sandstone") );  
  
    ts1.write( "Spiderman", new Integer(60), new Rock("Granite") );
    ts1.write( "Wonder Woman", new Integer(55), new Rock("Pumice") );
    ts1.write( "Batman", new Integer(65), new Rock("Ebony") );
    ts1.write( "Robin", new Integer(35), new Rock() );
    
    // Alternatively, for Index queries, we could have written the tuples with NAMED fields for NAME and AGE.
    ts2.write( new Field("Superheros", "Superman"), new Field("Age", 75), new Rock() );
    ts2.write( new Field("Superheros", "Spiderman"), new Field("Age", 60), new Rock("Granite") );
    ts2.write( new Field("Superheros", "Wonder Woman"), new Field("Age", 55), new Rock("Pumice") );
    ts2.write( new Field("Superheros", "Batman"), new Field("Age", 65), new Rock("Ebony") );
    ts2.write( new Field("Superheros", "Robin"), new Field("Age", 35), new Rock() );
  } catch ( TupleSpaceException tse) {
    Debug.out(tse);
    System.exit(1);
  }
	try { 
    // This is a regular structure match query, 
    // where the query values are fed directly into the read operator.  
    // In this example, the query will return the first tuple of the form
    //   < "Superman", 75, Rock("Kryptonite") >.
    Debug.out("Issue regular template Query. It should return 1 Superman"); 
    resultTuple = ts1.read( "Superman", new Integer(75), new Rock("Kryptonite") );
    if (resultTuple == null) {
      Debug.out(0,"Failure in template Query");
      Debug.setDebugOn(true);
    }

    Debug.out("Results: " + resultTuple);
    
    // The Match Query has similar function as the regular structure 
    // match query, but it takes a query tuple as input. 
    // In this example, the query will return ALL TUPLES of the form 
    //   < "Superman", 75, Rock >, where the values for the 
    // third parameter, Rock, can be any valid Rock value.
    Debug.out("Issue match Query. It should return 2 Superman obj"); 
    Field aRock =   new Field(Rock.class);
    queryTuple = new Tuple("Superman", new Integer(75), aRock);
    resultSetTuple = ts1.scan(new MatchQuery(  queryTuple ));
    if (resultSetTuple.numberOfFields() != 2) {
      Debug.out(0,"Failure in match Query");
      Debug.setDebugOn(true);
    }

    Debug.out("Results: " + resultSetTuple);
		
		// The Index Query is either an exact match or a range.
		//  In this example, it is an exact match on the value 
		//  "Spiderman".   This query will return 
		//  ALL TUPLES OF ANY STRUCTURE that have a 
		//  Superhero field of the String type, with the value "Spiderman".
		Debug.out("Issue index Query. It should return a Spiderman");
  		queryTuple = new Tuple(new IndexQuery("Superheros", "Spiderman"));
		resultSetTuple = ts2.scan( queryTuple );
    if (resultSetTuple.numberOfFields() != 1) {
      Debug.out(0,"Failure in Index Query");
      Debug.setDebugOn(true);
    }

		Debug.out("Results: " + resultSetTuple);
		
		// This is an example of an Index Query using a Range predicate.
		// This query will return ALL TUPLES OF ANY STRUCTURE that 
		//  have a Superhero name in the range of "A" through "L".
	

		Debug.out("Issue index Query with Range. It should return Batman");  		
		queryTuple = new Tuple(new IndexQuery("Superheros", new Range("A", "L")));
		resultSetTuple = ts2.scan( queryTuple );
    if (resultSetTuple.numberOfFields() != 1) {
      Debug.out(0,"Failure in Index Query with Range");
      Debug.setDebugOn(true);
    }

		Debug.out("Results: " + resultSetTuple);
		
		// This is an example of an And Query. 
		//  And and Or Queries can be arbitrarily nested and used 
		//  in any combination with other query types. 
		//  This query will return ALL TUPLES OF ANY STRUCTURE 
		//  that have a name in the range of "L" through "Z" 
		//  and an age in the range of  10 through 50.
		Debug.out("Issue index Query using AND.  It should return Robin");  
		queryTuple = new Tuple( new AndQuery( 
               new IndexQuery("Superheros", new Range("L", "Z")),
               new IndexQuery("Age", new Range(new Integer(10), new Integer(50)))
               	));
		resultSetTuple = ts2.scan(queryTuple);
    if (resultSetTuple.numberOfFields() != 1) {
      Debug.out(0,"Failure in And Query");
      Debug.setDebugOn(true);
    }

		Debug.out("Results: " + resultSetTuple);
		
		// This example of an Or Query is left as an exercise to the reader.
		Debug.out("Issue index Query using OR. It should return Robin and Superman ");  
		queryTuple = new Tuple(new OrQuery( 
                         new IndexQuery("Age", new Range(new Integer(10), new Integer(40))),
                         new IndexQuery("Age", new Range(new Integer(70), new Integer(90)))
                         	));
		resultSetTuple = ts2.scan(queryTuple);
    if (resultSetTuple.numberOfFields() != 2) {
      Debug.out(0,"Failure in Or Query");
      Debug.setDebugOn(true);
    }
      
		Debug.out("Results: " + resultSetTuple);
    Debug.out(0,"SuperHeros example completed"); 
		
  } catch ( TupleSpaceException tse) {
		Debug.out(0,tse);
		System.exit(1);
	}
}



  /*
  ***************************************************************************
  ** ** main    **
  ** *************
  */
  /**
  ** This is an application so we have to have a main that gets
  ** control and picks out any parameters
  **    java  ....SuperHeros   hostname
  **
  */	
public static void 
main( String argv[] ) {
	
	
  if (argv.length > 0) 
    _host = argv[0];      // if user specified server host
  if ((argv.length > 1) && (argv[1].equals("-D")) ) {
    Debug.setDebugOn(true);
    //TupleSpace.setDebug(true);
  }
      	
  SuperHeros sh = new SuperHeros();
  sh.init();  	
	System.exit(1);
} // end main



  /*
  ***************************************************************************
  ** ** Rock (innerClass   **
  ** ***********************
  */
  /**
  **  This InnerClass defines a simple Rock object.  
  **  It is very simple.  It has contains only a string that 
  **  is the name of the rock.
  ** 
  **  But there are some important things to note.
  **    Because we are going to write it to TupleSpace, it has
  **    to be Serializable.  
  **
  **    Because we are going to be expecting TupleSpace to find
  **    matching Rocks, we need to be sure that it has an 
  **    equals method that will do what we want.  In our case,
  **    we compare the names of the rock to see if they are 
  **    equal.
  **
  */
class Rock implements Serializable {
	  private String _rock = "";

/**
** Default constructor assigns a mystery name
**
*/
	  
public Rock() {
	_rock = "Kryptonite" ;
}
/**
** Constructor given a parameter with the name of the Rock
**
*/
public Rock(String rock)	{
	_rock = rock;
}

/**
** Return the name of the Rock 
*/
public String 
getName() {
	return _rock;
}

/**
** Return true if the names of the Rock match
**
** @param A reference to another Rock object
*/
public boolean 
equals(Object otherRock) {
	if ( ! (otherRock instanceof Rock) ) 
		return false;
	if ( ((Rock)otherRock).getName().equals(_rock)) 
		return true;
	else
		return false;
}		
/**
** Return a the name of the Rock
**
** 
*/
public String
toString() {
	return "Rock="+_rock;
}


} // end class Rock

} // class SuperHeros

/*
$History: SuperHeros.java $
 * 
 * *****************  Version 5  *****************
 * User: Jthomas      Date: 12/01/98   Time: 11:09a
 * Updated in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/simple
 * changes due to move of Query interface to client side. other minor
 * changes
 * 
 * *****************  Version 4  *****************
 * User: Jthomas      Date: 9/30/98    Time: 6:45p
 * Updated in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/simple
 * upgrade examples for new release
 * 
 * *****************  Version 3  *****************
 * User: Jthomas      Date: 9/16/98    Time: 9:18a
 * Updated in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/simple
 * changes required for Transaction processing
 * 
 * *****************  Version 2  *****************
 * User: Jthomas      Date: 3/04/98    Time: 7:43p
 * Updated in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/simple
 * get rid of those ugly makeField calls
 * 
 * *****************  Version 1  *****************
 * User: Toby         Date: 1/23/98    Time: 9:55a
 * Created in $/GCS/Development/TSpaces/Java/com/ibm/tspaces/examples/simple
 * 
 * *****************  Version 3  *****************
 * User: Jthomas      Date: 12/10/97   Time: 8:29p
 * Updated in $/GCS/Development/bluespaces/Java/com/ibm/bluespaces/examples/simple
 * add System.exit to bypass AIX Java problem
 * 
 * *****************  Version 2  *****************
 * User: Jthomas      Date: 12/09/97   Time: 7:25a
 * Updated in $/GCS/Development/bluespaces/Java/com/ibm/bluespaces/examples/simple
 * Completed the rest of the queries.
 * 
 * *****************  Version 1  *****************
 * User: Jthomas      Date: 12/05/97   Time: 10:13a
 * Created in $/GCS/Development/bluespaces/Java/com/ibm/bluespaces/examples/simple
*/
/* $Log: SuperHeros.java,v $
/* Revision 2.1  1999/11/05 22:22:40  estesp
/* Update revision number to 2.1 on all files
/*
/* Revision 1.1.1.1  1999/11/05 16:24:53  estesp
/* Imported 2.1.0 release into Austin CVS
/*
 * Revision 1.4  1999/10/08 02:14:05  jthomas
 * minor debug output change
 *
 * Revision 1.3  1999/09/08 15:31:37  jthomas
 * Make the tests more self checking and easier to run
 *
 * Revision 1.2  1999/06/17 05:39:47  thodes
 *   Updated the inital checkin to append the "Log" field and
 * convert CR/LF to CR (for win/unix interop).
 *
 *   The inital checkin lower-cased directrory names, and omitted
 * many dirs/files that will added later, e.g., MoDAL stuff.
 *
 * All of the above will need to be done to all VSS-to-CVS
 * converted sources.  In summary, in moving from VSS to CVS, do this:
 *  - lower-case dir names
 *  - CR/LF --> CR
 *  - append CVS "Log" entties
 *
 * (a script that helps with #2 and #3 is in
 *     tspaces1:~thodes/bin/update-keywords.sh)
 * 
 */
